package com.study.reflect.demo.generic;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

import org.junit.Test;

/**
* @Name: GenericReflectDemo
* @Description: 使用反射操作泛型测试类
* 说明：
* 	操作接口上的泛型；
* 	操作类上的泛型；
* 	操作属性上的泛型；
* 	操作方法上的泛型：
* 		1、获取参数上的泛型
* 			1、获取方法中的参数对象；
* 				Method方法类：
* 					Type[] getGenericParameterTypes()  按照声明顺序返回 Type参数对象的数组，这些对象描述了此 Method对象所表示的方法的形参类型的。
* 			2、获取参数中的泛型的实际类型对象
* 					ParameterizedType参数类型接口：
* 						Type[] getActualTypeArguments()  返回表示此类型实际类型参数的 Type对象的数组。
* 		2、获取返回值上的泛型
* 			1、获取方法上的返回值类型对象；
* 				Type getGenericReturnType()   返回表示由此 Method 对象所表示方法的正式返回类型的 Type 对象。
* 			2、获取返回值类型中的泛型的实际类型对象；
* 				Type[] getActualTypeArguments()  返回表示此类型实际类型参数的 Type对象的数组。
* @Author: 李超	lc_jack@foxmail.com
* @CreateDate: 2017-1-19 上午11:58:07 
* @Version: V1.0
 */
public class GenericReflectDemo {
	
	/**
	* @Name: test01
	* @Description: 测试带泛型参数的方法
	* @Author: 李超	lc_jack@foxmail.com
	* @Version: V1.0
	* @CreateDate: 2017-1-19 下午12:02:08
	* @Parameters: @param userMap
	* @Parameters: @param userList
	* @Return: void
	 */
	public void test01(Map<String, User> userMap, List<User> userList) {
		System.out.println("使用反射操作方法中的泛型参数!");
	}
	
	/**
	* @Name: opeGenericParam
	* @Description: 获取方法中参数的泛型的实际类型
	* @Author: 李超	lc_jack@foxmail.com
	* @Version: V1.0
	* @CreateDate: 2017-1-19 下午12:04:18
	* @Parameters: 
	* @Return: void
	 */
	@Test
	public void opeGenericParam() throws Exception {
		//获取类的字节码文件
		Class clazz = Class.forName("com.study.reflect.demo.generic.GenericReflectDemo") ;
		//获取待泛型参数的方法对象
		Method test01 = clazz.getDeclaredMethod("test01", Map.class, List.class) ;
		//取消权限访问检查
		test01.setAccessible(true) ;
		//获取方法上所有的参数
		Type[] paramTypes = test01.getGenericParameterTypes() ;
		for (Type paramType : paramTypes) {
			//输出参数信息
			System.out.println("方法上的参数：" + paramType);
			//获取参数的所有泛型的实际类型对象
			if(paramType instanceof ParameterizedType) {
				Type[] genericTypes = ((ParameterizedType) paramType).getActualTypeArguments() ; 
				for (Type genericType : genericTypes) {
					System.out.println("参数泛型类型：" + genericType);
				}
			}
		}
	}
	
	/**
	* @Name: test02
	* @Description: 获取方法的返回值中的泛型的实际类型
	* @Author: 李超	lc_jack@foxmail.com
	* @Version: V1.0
	* @CreateDate: 2017-1-19 下午6:46:37
	* @Parameters: @return
	* @Return: Map<String,User>
	 */
	public Map<String, User> test02() {
		System.out.println("使用反射获取方法的返回值类型中的泛型的实际类型");
		return null ;
	}
	
	@Test
	public void getReturnGeneric() throws Exception {
		//获取类的字节码文件对象
		Class clazz = Class.forName("com.study.reflect.demo.generic.GenericReflectDemo") ;
		//获取指定的方法对象
		Method test02 = clazz.getDeclaredMethod("test02") ;
		//获取方法的返回值类型对象
		Type returnType = test02.getGenericReturnType() ;
		System.out.println(returnType);
		//获取返回值类型中的所有泛型对象数组
		if(returnType instanceof ParameterizedType) {
			Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments() ;
			//遍历获取每一个泛型对象
			for (Type genericType : genericTypes) {
				System.out.println("返回值类型中泛型的实际类型：" + genericType);
			}
		}
	}
	
	/**
	* @Name: getFieldGeneric
	* @Description: 获取属性上的泛型的实际类型
	* @Author: 李超	lc_jack@foxmail.com
	* @Version: V1.0
	* @CreateDate: 2017-1-19 下午7:08:30
	* @Parameters: 
	* @Return: void
	 */
	@Test
	public void getFieldGeneric() throws Exception {
		//获取类的字节码文件对象
		Class clazz = Class.forName("com.study.reflect.demo.generic.User") ;
		//获取类的无参构造方法对象
		Constructor con = clazz.getDeclaredConstructor() ;
		//取消权限访问检查
		con.setAccessible(true) ;
		//创建类的实例化对象
		User user = (User) con.newInstance() ;
		System.out.println(user);
		//获取类中指定的属性对象
		Field citiesField = clazz.getDeclaredField("cities") ;
		//取消权限访问检查
		citiesField.setAccessible(true) ;
		System.out.println(citiesField);
		//获取属性的类型对象
		Type FieldType = citiesField.getGenericType() ;
		System.out.println(FieldType);
		//获取属性上泛型的实际类型
		if(FieldType instanceof ParameterizedType) {
			 Type[] genericTypes = ((ParameterizedType) FieldType).getActualTypeArguments() ;
			 for (Type genericType : genericTypes) {
				System.out.println(genericType);
			}
		}
	}
	
	
	
}

















